﻿using IOP.Models.Message.MQTT;
using IOP.Models.Tree.BinaryTree;
using System;

namespace IOP.Pulsar.MQTT.Client
{
    /// <summary>
    /// MQTT客户端服务
    /// </summary>
    public class MQTTClientService : IMQTTClientService
    {
        /// <summary>
        /// 客户端
        /// </summary>
        private ConcurrentRBTree<string,MQTTClient> Clients { get; set; }

        /// <summary>
        /// 构造函数
        /// </summary>
        public MQTTClientService()
        {
            Clients.Put("Root", null);
        }

        /// <summary>
        /// 连接
        /// </summary>
        /// <param name="option"></param>
        /// <returns></returns>
        public MQTTClient Connect(Action<MQTTOption> option)
        {
            var mqtt = new MQTTClient();
            mqtt.Connect(option);          
            Clients.Put(mqtt.ClientId, mqtt);
            return mqtt;
        }
        /// <summary>
        /// 重连
        /// </summary>
        /// <param name="client"></param>
        /// <returns></returns>
        public MQTTClient Reconnect(MQTTClient client)
        {
            if (client.IsDispose)
            {
                Clients.Delete(client.ClientId);
                throw new MQTTClientException(client, "this client is already dispose");
            }
            else if (!client.IsConnected)
            {
                client.Reconnect();
                if(!client.IsConnected) throw new MQTTClientException(client, "reconnect failed");
            }
            return client;
        }
        /// <summary>
        /// 重连
        /// </summary>
        /// <param name="client"></param>
        /// <param name="option"></param>
        /// <returns></returns>
        public MQTTClient Reconnect(MQTTClient client, Action<MQTTOption> option)
        {
            if (client.IsDispose)
            {
                client = new MQTTClient();
                Clients.Delete(client.ClientId);
                client.Connect(option);
                if (client.IsConnected) Clients.Put(client.ClientId, client);
                else throw new MQTTClientException(client, "reconnect failed");
            }
            else
            {
                Clients.Delete(client.ClientId);
                client.Reconnect(option);
                if (client.IsConnected) Clients.Put(client.ClientId, client);
                else throw new MQTTClientException(client, "reconnect failed");
            }
            return client;
        }
        /// <summary>
        /// 重连
        /// </summary>
        /// <param name="clientName"></param>
        /// <returns></returns>
        public MQTTClient Reconnect(string clientName)
        {
            var client = GetClient(clientName);
            Reconnect(client);
            return client;
        }
        /// <summary>
        /// 重连
        /// </summary>
        /// <param name="clientName"></param>
        /// <param name="option"></param>
        /// <returns></returns>
        public MQTTClient Reconnect(string clientName, Action<MQTTOption> option)
        {
            var client = GetClient(clientName);
            Reconnect(client, option);
            return client;
        }

        /// <summary>
        /// 发布
        /// </summary>
        /// <param name="client"></param>
        /// <param name="topicName"></param>
        /// <param name="body"></param>
        /// <param name="qoSType"></param>
        /// <param name="retain"></param>
        public void SendPublish(MQTTClient client, string topicName, byte[] body, QoSType qoSType = QoSType.QoS0, bool retain = false)
        {
            if (client == null) throw new ArgumentNullException(nameof(client));
            client.SendPublish(topicName, body, qoSType, retain);
        }
        /// <summary>
        /// 发布
        /// </summary>
        /// <param name="clientName"></param>
        /// <param name="topicName"></param>
        /// <param name="body"></param>
        /// <param name="qoSType"></param>
        /// <param name="retain"></param>
        public void SendPublish(string clientName, string topicName, byte[] body, QoSType qoSType = QoSType.QoS0, bool retain = false)
        {
            var client = GetClient(clientName);
            client.SendPublish(topicName, body, qoSType, retain);
        }

        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="client"></param>
        /// <param name="topicFilters"></param>
        public void SendSubscribe(MQTTClient client, TopicFilter[] topicFilters)
        {
            if (client == null) throw new ArgumentNullException(nameof(client));
            client.SendSubscribe(topicFilters);
        }
        /// <summary>
        /// 订阅
        /// </summary>
        /// <param name="clientName"></param>
        /// <param name="topicFilters"></param>
        public void SendSubscribe(string clientName, TopicFilter[] topicFilters)
        {
            var client = GetClient(clientName);
            client.SendSubscribe(topicFilters);
        }

        /// <summary>
        /// 取消订阅
        /// </summary>
        /// <param name="client"></param>
        /// <param name="topicFilters"></param>
        public void SendUnsubscribe(MQTTClient client, string[] topicFilters)
        {
            if (client == null) throw new ArgumentNullException(nameof(client));
            client.SendUnsubscribe(topicFilters);
        }

        /// <summary>
        /// 取消订阅
        /// </summary>
        /// <param name="clientName"></param>
        /// <param name="topicFilters"></param>
        public void SendUnsubscribe(string clientName, string[] topicFilters)
        {
            var client = GetClient(clientName);
            client.SendUnsubscribe(topicFilters);
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="name"></param>
        public void Disconnect(string name)
        {
            var client = Clients[name];
            client?.Disconnect();
        }
        /// <summary>
        /// 断开连接
        /// </summary>
        /// <param name="client">目标客户端</param>
        public void Disconnect(MQTTClient client)
        {
            client?.Disconnect();
        }

        /// <summary>
        /// 获取客户端连接
        /// </summary>
        /// <param name="clientName"></param>
        /// <returns></returns>
        public MQTTClient GetClient(string clientName)
        {
            var client = Clients[clientName];
            if (client == null) throw new NullReferenceException($"Client didnt't found , the clientName is : {clientName}");
            return client;
        }

        /// <summary>
        /// 删除客户端
        /// </summary>
        /// <param name="client"></param>
        public void DeleteClient(MQTTClient client)
        {
            client.Dispose();
            Clients.Delete(client.ClientId);
        }

        /// <summary>
        /// 删除客户端
        /// </summary>
        /// <param name="clientId"></param>
        public void DeleteClient(string clientId)
        {
            var client = Clients[clientId];
            client?.Dispose();
            Clients.Delete(clientId);
        }
    }
}
